using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using DocumentCreationSystem.Models;

namespace DocumentCreationSystem.Services;

/// <summary>
/// BGE-M3向量化服务 - 与LM Studio的text-embedding-bge-m3模型集成
/// </summary>
public class BGEEmbeddingService : IVectorService
{
    private readonly ILogger<BGEEmbeddingService> _logger;
    private readonly IConfiguration _configuration;
    private readonly HttpClient _httpClient;
    private readonly Dictionary<string, VectorDocument> _vectorStore;
    private readonly string _embeddingUrl;

    public BGEEmbeddingService(ILogger<BGEEmbeddingService> logger, IConfiguration configuration, HttpClient httpClient)
    {
        _logger = logger;
        _configuration = configuration;
        _httpClient = httpClient;
        _vectorStore = new Dictionary<string, VectorDocument>();
        
        // 从配置中获取LM Studio的URL
        var lmStudioUrl = _configuration["AI:LMStudio:BaseUrl"] ?? "http://localhost:1234";
        _embeddingUrl = $"{lmStudioUrl}/v1/embeddings";
    }

    public async Task<bool> InitializeAsync()
    {
        try
        {
            // 测试连接到LM Studio
            var testResult = await CheckConnectionAsync();
            if (testResult)
            {
                _logger.LogInformation("BGE-M3向量化服务初始化成功");
                return true;
            }
            else
            {
                _logger.LogWarning("无法连接到LM Studio，将使用备用向量化方法");
                return true; // 仍然返回true，使用备用方法
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "BGE-M3向量化服务初始化失败");
            return false;
        }
    }

    public async Task<float[]> EmbedTextAsync(string text)
    {
        try
        {
            // 首先尝试使用LM Studio的BGE-M3模型
            var embedding = await GetBGEEmbeddingAsync(text);
            if (embedding != null)
            {
                return embedding;
            }

            // 如果失败，使用备用方法
            _logger.LogWarning("BGE-M3向量化失败，使用备用方法");
            return GenerateFallbackEmbedding(text);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文本向量化失败");
            return GenerateFallbackEmbedding(text);
        }
    }

    /// <summary>
    /// 使用LM Studio的BGE-M3模型生成向量
    /// </summary>
    private async Task<float[]?> GetBGEEmbeddingAsync(string text)
    {
        try
        {
            var requestBody = new
            {
                model = "text-embedding-bge-m3",
                input = text,
                encoding_format = "float"
            };

            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            var response = await _httpClient.PostAsync(_embeddingUrl, content);
            
            if (response.IsSuccessStatusCode)
            {
                var responseJson = await response.Content.ReadAsStringAsync();
                var embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponse>(responseJson);
                
                if (embeddingResponse?.data?.Length > 0)
                {
                    return embeddingResponse.data[0].embedding;
                }
            }
            else
            {
                _logger.LogWarning($"BGE-M3 API请求失败: {response.StatusCode}");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "调用BGE-M3 API失败");
        }

        return null;
    }

    /// <summary>
    /// 备用向量化方法
    /// </summary>
    private float[] GenerateFallbackEmbedding(string text)
    {
        const int vectorSize = 1024; // BGE-M3的向量维度
        var vector = new float[vectorSize];
        var hash = text.GetHashCode();
        var random = new Random(hash);

        // 基于文本特征生成确定性向量
        var words = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        var wordCount = words.Length;
        var avgWordLength = words.Any() ? words.Average(w => w.Length) : 0;
        var uniqueWords = words.Distinct().Count();
        var chineseChars = text.Count(c => c >= 0x4e00 && c <= 0x9fff);

        for (int i = 0; i < vectorSize; i++)
        {
            // 结合多种文本特征
            var baseValue = (float)(random.NextDouble() * 2 - 1);
            var textFeature = (float)Math.Sin(i * avgWordLength / 100.0) * 0.3f;
            var lengthFeature = (float)Math.Cos(i * wordCount / 50.0) * 0.2f;
            var uniqueFeature = (float)Math.Sin(i * uniqueWords / 30.0) * 0.1f;
            var chineseFeature = (float)Math.Cos(i * chineseChars / 20.0) * 0.15f;

            vector[i] = baseValue + textFeature + lengthFeature + uniqueFeature + chineseFeature;
        }

        // 归一化向量
        var magnitude = Math.Sqrt(vector.Sum(x => x * x));
        if (magnitude > 0)
        {
            for (int i = 0; i < vectorSize; i++)
            {
                vector[i] = (float)(vector[i] / magnitude);
            }
        }

        return vector;
    }

    public async Task<string> AddDocumentAsync(string vectorId, string content, Dictionary<string, object>? metadata = null)
    {
        try
        {
            var chunks = SplitTextIntoChunks(content, 500, 50);
            var embedding = await EmbedTextAsync(content);
            
            var vectorDoc = new VectorDocument
            {
                Id = vectorId,
                DocumentId = 0,
                Content = content,
                Chunks = chunks,
                Metadata = metadata ?? new Dictionary<string, object>(),
                CreatedAt = DateTime.Now,
                Embedding = embedding
            };

            _vectorStore[vectorId] = vectorDoc;
            _logger.LogInformation($"添加文档向量成功，向量ID: {vectorId}");
            return vectorId;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"添加文档向量失败，向量ID: {vectorId}");
            throw;
        }
    }

    public async Task<List<VectorSearchResult>> SearchAsync(string query, string collectionName = "documents", int limit = 10, float threshold = 0.7f)
    {
        try
        {
            var queryEmbedding = await EmbedTextAsync(query);
            var results = new List<VectorSearchResult>();

            foreach (var kvp in _vectorStore)
            {
                var vectorDoc = kvp.Value;
                if (vectorDoc.Embedding != null)
                {
                    var similarity = CalculateCosineSimilarity(queryEmbedding, vectorDoc.Embedding);
                    
                    if (similarity >= threshold)
                    {
                        results.Add(new VectorSearchResult
                        {
                            Id = vectorDoc.Id,
                            Score = similarity,
                            Content = vectorDoc.Content.Length > 200 ? 
                                vectorDoc.Content.Substring(0, 200) + "..." : 
                                vectorDoc.Content,
                            DocumentId = vectorDoc.DocumentId,
                            ChunkIndex = 0,
                            Metadata = vectorDoc.Metadata
                        });
                    }
                }
            }

            return results.OrderByDescending(r => r.Score).Take(limit).ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"向量搜索失败，查询: {query}");
            throw;
        }
    }

    /// <summary>
    /// 计算余弦相似度
    /// </summary>
    private float CalculateCosineSimilarity(float[] vector1, float[] vector2)
    {
        if (vector1.Length != vector2.Length)
            return 0f;

        var dotProduct = 0f;
        var magnitude1 = 0f;
        var magnitude2 = 0f;

        for (int i = 0; i < vector1.Length; i++)
        {
            dotProduct += vector1[i] * vector2[i];
            magnitude1 += vector1[i] * vector1[i];
            magnitude2 += vector2[i] * vector2[i];
        }

        magnitude1 = (float)Math.Sqrt(magnitude1);
        magnitude2 = (float)Math.Sqrt(magnitude2);

        if (magnitude1 == 0f || magnitude2 == 0f)
            return 0f;

        return dotProduct / (magnitude1 * magnitude2);
    }

    public List<string> SplitTextIntoChunks(string text, int chunkSize = 500, int overlap = 50)
    {
        var chunks = new List<string>();
        var sentences = text.Split(new[] { '。', '！', '？', '\n' }, StringSplitOptions.RemoveEmptyEntries);
        
        var currentChunk = new StringBuilder();
        var currentLength = 0;

        foreach (var sentence in sentences)
        {
            if (currentLength + sentence.Length > chunkSize && currentChunk.Length > 0)
            {
                chunks.Add(currentChunk.ToString().Trim());
                
                // 保留重叠部分
                var overlapText = GetLastCharacters(currentChunk.ToString(), overlap);
                currentChunk.Clear();
                currentChunk.Append(overlapText);
                currentLength = overlapText.Length;
            }

            currentChunk.Append(sentence + "。");
            currentLength += sentence.Length + 1;
        }

        if (currentChunk.Length > 0)
        {
            chunks.Add(currentChunk.ToString().Trim());
        }

        return chunks;
    }

    public async Task<bool> CheckConnectionAsync()
    {
        try
        {
            var testText = "测试连接";
            var embedding = await GetBGEEmbeddingAsync(testText);
            return embedding != null;
        }
        catch
        {
            return false;
        }
    }

    private string GetLastCharacters(string text, int count)
    {
        if (text.Length <= count) return text;
        return text.Substring(text.Length - count);
    }

    // 实现其他接口方法的简化版本
    public async Task<bool> CreateCollectionAsync(string collectionName, int vectorSize = 1024) => true;
    public async Task<bool> DeleteCollectionAsync(string collectionName) => true;
    public async Task<List<VectorRecord>> AddDocumentVectorsAsync(int documentId, List<string> textChunks) => new();
    public async Task<bool> UpdateDocumentVectorsAsync(int documentId, List<string> textChunks) => true;
    public async Task<bool> DeleteDocumentVectorsAsync(int documentId) => true;
    public async Task<List<string>> GetRelevantContextAsync(string query, int? projectId = null, int limit = 5) => new();
    public async Task<VectorCollectionInfo?> GetCollectionInfoAsync(string collectionName) => null;
    public async Task<bool> RebuildIndexAsync(int projectId) => true;
}

/// <summary>
/// BGE-M3 API响应模型
/// </summary>
public class EmbeddingResponse
{
    public EmbeddingData[]? data { get; set; }
    public string? model { get; set; }
    public Usage? usage { get; set; }
}

public class EmbeddingData
{
    public float[]? embedding { get; set; }
    public int index { get; set; }
    public string? @object { get; set; }
}

public class Usage
{
    public int prompt_tokens { get; set; }
    public int total_tokens { get; set; }
}


